(function (global, factory) {
    // @ts-ignore
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : // @ts-ignore
        typeof define === 'function' && define.amd ? define(factory) : // @ts-ignore
            (global = global || self, global.Wmc = factory());
}(this, function () {

    interface WsOptions {
        url: string
        schema?: string | string[] | undefined
        open?: (ev: Event) => any
        close?: (ev: CloseEvent) => any
        error?: (ev: Event) => any
        message: (ev: MessageEvent, data: string) => any
    }

    interface WebSocketType {
        ws: WebSocket
        close: (code?: number, reason?: string) => void
        join: (roomId: string) => void
        leave: (roomId: string) => void
        register: (userId: string) => void
        send: (to: string, type: string, message: string) => void
        broadcast: (message: string) => void
        sendRaw: (message: string) => void
    }

    const ToSystem = 'system' // 系统消息
    const ToGlobal = 'global' // 广播消息

    const TypeJoin = "join"     // 加入房间
    const TypeLeave = "leave"    // 离开房间
    const TypeRegister = "register" // 注册客户端身份

    const TypeRoom = "room"     // 房间类消息
    const TypePersonal = "personal" // 个人类消息
    const TypeGroup = "group" // 用户组类消息

    function LWS(options: WsOptions): WebSocketType {
        if (!window['WebSocket']) {
            throw new Error('Your browser does not support WebSocket')
        }

        // 准备发送数据包
        const preparePayload = function (to: string, type: string, message: string): string {
            return JSON.stringify({
                to: to,
                type: type,
                content: message
            })
        }

        const ws = new WebSocket(options.url, options.schema)

        const onOpen = function (ev: Event) {
            if (options.open) {
                options.open(ev)
            }
        }

        const onClose = function (ev: CloseEvent) {
            if (options.close) {
                options.close(ev)
            }
        }

        const onError = function (ev: Event) {
            if (options.error) {
                options.error(ev)
            }
        }

        const onMessage = function (ev: MessageEvent) {
            if (options.message) {
                const contents = ev.data.split(String.fromCharCode(1))
                contents.forEach((content: string) => {
                    options.message(ev, content)    
                });
            }
        }

        ws.onopen = onOpen
        ws.onclose = onClose
        ws.onerror = onError
        ws.onmessage = onMessage

        return {
            ws: ws,
            close: function (code?: number, reason?: string) {
                ws.close(code, reason)
            },
            join: function (roomId: string) {
                ws.send(preparePayload(ToSystem, TypeJoin, roomId));
            },
            leave: function (roomId: string) {
                ws.send(preparePayload(ToSystem, TypeLeave, roomId));
            },
            register: function (userId: string) {
                ws.send(preparePayload(ToSystem, TypeRegister, userId));
            },
            send: function (to: string, type: string, message: string) {
                ws.send(preparePayload(to, type, message));
            },
            broadcast: function (message: string) {
                ws.send(preparePayload(ToGlobal, "", message));
            },
            sendRaw: function (message: string) {
                ws.send(message)
            }
        }
    }
    LWS.ToSystem = ToSystem // 系统消息
    LWS.ToGlobal = ToGlobal // 广播消息

    LWS.TypeJoin = TypeJoin     // 加入房间
    LWS.TypeLeave = TypeLeave    // 离开房间
    LWS.TypeRegister = TypeRegister // 注册客户端身份

    LWS.TypeRoom = TypeRoom     // 房间类消息
    LWS.TypePersonal = TypePersonal // 个人类消息
    LWS.TypeGroup = TypeGroup // 用户组类消息
    
    return LWS;
}));